#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@IDE     ：PyCharm 
@Author  ：kiway
@Date    ：2024/7/26 14:13 
"""

import inspect
import time

import ccxt.pro
from .BaseStrategy import Strategy__
from .Schedual import LoopRunTask
from .AccountEngine import AccountEngine
from .. import logger

from .BaseEngine import (EVENT_BAR,
                         EVENT_TICK,
                         EVENT_ORDERBOOK,
                         EVENT_CROSSBAR,
                         EVENT_AGGTRADE,
                         EVENT_PrORDER,
                         EVENT_PsORDER,
                         EVENT_POSITIONS_UPDATE, EVENT_BALANCE_UPDATE, EVENT_ORDER_STATUS_UPDATE,
                         EVENT_SWITCH,
                         EVENT_POLYBAR
                         )

from .EventEngine import EventEngine

from .MarketEngine import MarketEngine
from typing import List, Tuple, Dict

from .BaseEngine import BaseEngine
from .RiskMangerEngine import RiskEngine
from .syn_container import ParrallEngine
from .TradingEngine import TradingEngine
from ..logger import pretty_print
from .DataPersist import LatestRecord
from ..config import config


# 业务类
class MainLoopEngine(BaseEngine):

    def __init__(self, schedual_interval=10000):
        super().__init__("主引擎", None)
        self.looptask = LoopRunTask()
        self.strategy_config_ls: Tuple[Strategy__, List[Dict]] = None
        self.test_mode = config.sandbox_mode
        self.schedual_interval = schedual_interval

        self.main_engine: EventEngine = None
        self.risk_engine: RiskEngine = None
        self.account_engine: AccountEngine = None
        self.market_engine: MarketEngine = None
        self.trading_engine: TradingEngine = None

        self.overall_config = config

        self.exchange_id = config.exchange_id

    def add_strategy(self, strategy, configs: List[Dict]):
        """实现多策略运行框架"""

        self.strategy_config_ls = (strategy, configs)

    def init(self):

        logger.initLogger(level="INFO")
        self.main_engine = EventEngine()

        config_task, future_ls, spot_ls, sync_strategy = self.get_tasks()

        self.account_engine = AccountEngine(main_engine=self.main_engine)

        sync_strategy.set_main_engine(self.main_engine)

        self.parall_engine = ParrallEngine(future_ls + spot_ls,
                                           main_engine=self.main_engine, sync_strategy=sync_strategy)

        self.market_engine = MarketEngine(config_task=config_task, future_ls=future_ls, spot_ls=spot_ls,
                                          main_engine=self.main_engine)

        self.trading_engine = TradingEngine(self.main_engine)
        self.risk_engine = RiskEngine(self.main_engine)

        self.main_engine.register(EVENT_BAR, self.parall_engine.put_self_mq)
        self.main_engine.register(EVENT_POLYBAR, self.parall_engine.put_self_mq)
        # self.main_engine.register(EVENT_SWITCH, self.zmq_msg.put)
        # self.main_engine.register(EVENT_TICK, self.strategy_engine.put_self_mq)
        # self.main_engine.register(EVENT_ORDERBOOK, self.strategy_engine.put_self_mq)
        # self.main_engine.register(EVENT_CROSSBAR, self.strategy_engine.put_self_mq)
        # self.main_engine.register(EVENT_AGGTRADE, self.strategy_engine.put_self_mq)
        self.main_engine.register(EVENT_PsORDER, self.trading_engine.put_self_mq)

        self.main_engine.register(EVENT_PrORDER, self.risk_engine.put_self_mq)

        # self.main_engine.register(EVENT_POSITIONS_UPDATE, self.risk_engine.put_self_mq)
        # self.main_engine.register(EVENT_BALANCE_UPDATE, self.risk_engine.put_self_mq)

        # self.main_engine.register(EVENT_POSITIONS_UPDATE, self.strategy_engine.put_self_mq)
        # self.main_engine.register(EVENT_BALANCE_UPDATE, self.strategy_engine.put_self_mq)
        # self.main_engine.register(EVENT_ORDER_STATUS_UPDATE, self.strategy_engine.put_self_mq)

        # self.main_engine.register(EVENT_POSITIONS_UPDATE, self.trading_engine.put_self_mq)
        # self.main_engine.register(EVENT_BALANCE_UPDATE, self.trading_engine.put_self_mq)
        # self.main_engine.register(EVENT_ORDER_STATUS_UPDATE, self.trading_engine.put_self_mq)

    def _inspect_on_method(self, st):

        market_callback = {"bar_istrue": False,
                           "tick_istrue": False,
                           "orderbook_istrue": False,
                           "allbar_istrue": False,
                           "aggTrade_istrue": False}

        methods = dict(inspect.getmembers(st, predicate=inspect.ismethod))

        methods_on_bar = methods.get("on_bar", None)
        if "Strategy__.on_bar" not in str(methods_on_bar):
            market_callback["bar_istrue"] = True

        methods_on_tick = methods.get("on_tick", None)
        if "Strategy__.on_tick" not in str(methods_on_tick):
            market_callback["tick_istrue"] = True

        methods_on_orderbook = methods.get("on_orderbook", None)
        if "Strategy__.on_orderbook" not in str(methods_on_orderbook):
            market_callback["orderbook_istrue"] = True

        methods_on_all_bar = methods.get("on_all_bar", None)
        if "Strategy__.on_all_bar" not in str(methods_on_all_bar):
            market_callback["allbar_istrue"] = True

        methods_on_all_bar = methods.get("on_agg_trade", None)
        if "Strategy__.on_agg_trade" not in str(methods_on_all_bar):
            market_callback["aggTrade_istrue"] = True

        return market_callback

    def get_tasks(self):
        """
        此函数用于分割若干任务到不同的进程里去
        """

        Stra, config_ls = self.strategy_config_ls
        st = Stra("sync_")
        market_callback = self._inspect_on_method(st)

        future_symbol_ls = None
        spot_symbols_ls = None

        exchange = {"id": self.exchange_id, "sandbox_mode": self.test_mode}
        tasks = {"strategy": Stra, "is_callback": market_callback, "exchange": exchange}

        for config in config_ls:

            if config["options"]["defaultType"] == "future":
                future_symbol_ls = config["symbols"]

            if config["options"]["defaultType"] == "spot":
                spot_symbols_ls = config["symbols"]

        return tasks, future_symbol_ls, spot_symbols_ls, st

    def _start(self):

        LatestRecord().clear()

        self.init()
        self.main_engine.start()
        self.account_engine.start()
        self.parall_engine.start()
        self.trading_engine.start()
        self.risk_engine.start()

        self.market_engine.start()
